package com.sk.util;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;

import java.io.*;
import java.util.*;

/**
 *
 * @Author jiaok
 * @Date 2023-12-05 10:34
 */
@Slf4j
public class YmlUtil {

    private final static DumperOptions OPTIONS = new DumperOptions();

    private static File file;

    private static InputStream ymlInputStream;


    private static Object CONFIG_MAP;

    private static Yaml yaml;

    static {
        //设置yaml读取方式为块读取
        OPTIONS.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
        //使用简单的文本格式，不包含任何额外的格式化或缩进。
        OPTIONS.setDefaultScalarStyle(DumperOptions.ScalarStyle.PLAIN);
        //格式化输出yml
        OPTIONS.setPrettyFlow(true);
    }

    public static void main(String[] args) {
        String fileName = "src/main/resources/templates/frame.yml";
        String key = "server.port";
        File file = new File(fileName);
        try {
            YmlUtil.setYmlFile(file);
            log.info("===========================  节点修改之前的值：{}  ===========================",YmlUtil.getValByKey(key));
            YmlUtil.saveOrUpdateByKey(key,9999);
            log.info("===========================  节点修改之后的值：{}  ===========================",YmlUtil.getValByKey(key));

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void bulkOperationConfig(String ymlPath,Map<String,Object> map) throws Exception {
        log.info("=========================== # YmlUtil.bulkOperationConfig #  ===========================");
        File file = new File(ymlPath);
        YmlUtil.setYmlFile(file);
        for (String key : map.keySet()) {
            YmlUtil.saveOrUpdateByKey(key,map.get(key));
        }
    }

    /**
     * 指定yml文件
     * @param file
     * @throws FileNotFoundException
     */
    public static void setYmlFile(File  file) throws FileNotFoundException {
        YmlUtil.file=file;
        if (ymlInputStream==null){
            setYmlInputStream(new FileInputStream(file));
        }
    }
    /**
     * 设置yml的文件输入流
     * @param fileInputStream  需要操作的文件输入流
     */
    private static void setYmlInputStream(FileInputStream fileInputStream) {

        ymlInputStream=fileInputStream;
        //传入yaml的格式
        yaml=new Yaml(OPTIONS);
        //获取读取所有yml的map键值对
        CONFIG_MAP=yaml.load(fileInputStream);
    }

    /**
     * 根据键获取值
     * 使用"@SuppressWarnings"  忽略编译器对类型转换的警告
     * @param key key
     * @return 查找到的值
     */
    @SuppressWarnings("unchecked")
    public static Object getValByKey(String key){
        //首先检测内存中的yml信息
        if (ymlInputStream == null){
            return null;
        }
        //将多个key进行划分
        String[] keys = key.split("\\.");
        //获取当前操作yml的所有map集合
        Object configMap=CONFIG_MAP;
        //对map进行多次划分
        for (String k : keys) {
            if (configMap instanceof  Map){
                /**
                 * 说明当前的配置文件键值对还具有键值对结构
                 * 获取筛选之后的结构
                 */
                configMap = ((Map<String,Object>) configMap).get(k);
            }else {
                //已经筛选出最终的结果
                break;
            }
        }
        //如果configMap为空，则说明没有指定的值，否则，筛选出的来的就是想要获取的值
        return configMap == null ? "":configMap;
    }
    /**
     *
     * @param key
     * @param value
     */
    public static void saveOrUpdateByKey(String key,Object value) throws Exception{
        KeyAndMap keyAndMap = new KeyAndMap(key).invoke();
        key = keyAndMap.getKey();
        Map<String, Object> map = keyAndMap.getMap();
        map.put(key, value);
        //将数据重新写回文件
        yaml.dump(CONFIG_MAP, new FileWriter(file));
    }

    public static void removeByKey(String key) throws Exception {
        KeyAndMap keyAndMap = new KeyAndMap(key).invoke();
        key = keyAndMap.getKey();
        Map<String, Object> map = keyAndMap.getMap();
        Map<String, Object> fatherMap = keyAndMap.getFatherMap();
        map.remove(key);
        if (map.size() == 0) {
            Set<Map.Entry<String, Object>> entries = fatherMap.entrySet();
            for (Map.Entry<String, Object> entry : entries) {
                if (entry.getValue() == map) {
                    fatherMap.remove(entry.getKey());
                }
            }
        }
        yaml.dump(CONFIG_MAP, new FileWriter(file));
    }
    @Getter
    private static class KeyAndMap {
        private String key;
        private Map<String, Object> map;
        /**
         * 用于移除节点
         */
        private Map<String, Object> fatherMap;

        public KeyAndMap(String key) {
            this.key = key;
        }

        @SuppressWarnings("unchecked")
        public KeyAndMap invoke() {
            if (file == null) {
                log.error("=========================== 请设置yml文件  ===========================");
            }
            if (null == CONFIG_MAP) {
                CONFIG_MAP = new LinkedHashMap<>();
            }
            String[] keys = key.split("\\.");
            key = keys[keys.length - 1];
            map = (Map<String, Object>) CONFIG_MAP;
            for (int i = 0; i < keys.length - 1; i++) {
                String s = keys[i];
                if (map.get(s) == null || !(map.get(s) instanceof Map)) {
                    map.put(s, new HashMap<>(4));
                }
                fatherMap = map;
                map = (Map<String, Object>) map.get(s);
            }
            return this;
        }
    }
}


